#!/usr/bin/evn python
"""
Module utils: utilities of the program.
Parts from genetrack atlas package.
10/12/2008
"""

import os, sys
import functools
import logging
import time
import csv
import tempfile

###############################################################################

def which(program):
    """
    Test if executable exists in PATH
    http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python
    """
    import os
    def is_exe(fpath):
        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)

    fpath, fname = os.path.split(program)
    if fpath:
        if is_exe(program):
            return program
    else:
        for path in os.environ["PATH"].split(os.pathsep):
            path = path.strip('"')
            exe_file = os.path.join(path, program)
            if is_exe(exe_file):
                return exe_file

    return None

def wc_line(infile):
    """
    Count lines of given file by calling wc
    """
    fd, ftmp = tempfile.mkstemp()
    command = "cat %s | wc -l > %s" % (infile, ftmp)
    os.system(command)

    num = int(open(ftmp).readline().rstrip())
    os.system("rm -f %s" % ftmp)

    return num

###############################################################################

def join_paths(*args):
    """
    Joins and normalizes a path
    """
    return os.path.abspath(os.path.join(*args))

###############################################################################

def get_logger(name='PYRNA', stream=sys.stdout):
    """
    Returns a logger
    >>> log = get_logger()
    >>> # use like so:
    >>> # log.info( 'info level message' )
    >>> # log.error( 'error level message' )
    """
    logger = logging.getLogger(name)

    # various details of logging
    #format = '%(levelname) %(asctime)-15s %(module)s.%(funcName)s: %(message)'

    format = '%(levelname)s %(module)s.%(funcName)s: %(message)s'

    logging.basicConfig(format=format, level=logging.DEBUG, stream=stream)
    return logger

################################################################################

def disable_loglevel( level=0 ):
    """
    Disables logging levels
    """
    level = str(level)
    value = dict(NOTSET=0, DEBUG=10, INFO=20, WARNING=30).get(level.upper(), 0)
    logging.disable( value )

log = get_logger()
info, error, warn, debug = log.info, log.error, log.warn, log.debug

def fatal( msg):
    "An error that will stop execution"
    error( msg )
    sys.exit()

################################################################################
#
# When the debug mode is off (False) trace backs are caught and only
# the error messages are displayed. 
#
def debug_mode( flag=True):
    global STOP_EXCEPTION
    if flag:
        STOP_EXCEPTION = None
    else:
        STOP_EXCEPTION = Exception

debug_on  = functools.partial(debug_mode, True)
debug_off = functools.partial(debug_mode, False)

# default debug mode is off
debug_off()

################################################################################

def stop_on_error( func ):
    """ 
    A decorator that stops the execution if there was an exception.
    Will also hide the actual source of the error. Run debug_off() to
    get full tracebacks.

    >>> @stop_on_error
    ... def foo():
    ...    pass
    """
    global STOP_EXCEPTION

    @functools.wraps(func)
    def stop( *args,**kargs ):
        try:
            result = func( *args, **kargs)
        except STOP_EXCEPTION, exc:
            sys.stderr.write( 'ERROR in %s: %s\n' % (func.func_name, exc) )
            sys.stderr.flush()
            sys.exit()
        return result
    return stop

################################################################################
        
class Tick(object):
    """
    A simple timer object to return elapsed times.

    >>> tick = Tick()
    >>> tick.format(30)
    '30.0 seconds'
    >>> tick.format(320)
    '5.3 minutes'
    >>> tick.format(3200)
    '53.3 minutes'
    >>> tick.format(30500)
    '8.5 hours'

    """
    def __init__(self):
        self.tick()

    def tick(self):
        self.start = time.time()

    def format(self, value):
        min1 = 60.0
        hour = 60 * min1
        if value < 60:
            return '%3.1f seconds' % value
        elif value < hour:
            return '%3.1f minutes' % (value/min1)
        else:
            return '%3.1f hours' % (value/hour)

    def tock(self):
        elapsed = time.time() - self.start
        self.tick()
        return self.format( elapsed )

################################################################################

def make_tempfile( fname=None, dir='', prefix='fsa', suffix='.fsa'):
    """
    Returns a filename and file path to a temporary file
    
    If the {tid} parameter is not specified it will generate a random id
    >>> make_tempfile(fname=1)[0]
    'img1.png'
    >>> len(make_tempfile())
    2
    """
    
    if fname == None:
        if dir:
            fd, fpath = tempfile.mkstemp(suffix=suffix, prefix=prefix, 
                                         dir=dir, text='wb')
        else:
            fd, fpath = tempfile.mkstemp(suffix=suffix, prefix=prefix, 
                                         text='wb')
        os.close(fd)
        head, fname = os.path.split( fpath )
    else:
        fname = '%s%s%s' % (prefix, fname, suffix)
        fpath = join_paths( dir, fname )

    return fname, fpath

################################################################################

